package controller.adder;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.Vector;

import javax.swing.JViewport;

import advance.GameMap;
import mapelements.foreground.MapLayer;

import controller.Controller;
import controller.ObjectAdderInformationContainer;
import errors.CoordinatesNotAcceptableException;
import errors.StratumNotFoundException;
import event.numberevent.StateNumber;
import gui.Display;

/**rappresenta un oggetto che gestisce il modo di aggiungere un MapLayer
 * all'interno della mappa. L'algoritmo dell'aggiunta del MapLayer nella mappa è il seguente:
 * <ul>
 *  <li>si carica la classe che si desidera inserire</li>
 *  <li>si esegue un click sinistro del mouse per inserire un punto</li>
 *  <li>se esegue un click destro del mouse per rimuovere il punto precedente</li>
 *  <li>si esegue doppio click sinistro del mouse per aggiungere un punto e per concludere il poligono da creare per il MapLayer</li>
 *  <li>si preme il pulsante "ESC" per eliminare l'intero poligono che si stava creando</li>
 * </ul>
 * 
 * finita la creazione di un poligono è possibile ripetere la procedura quante volte si desidera. Comunque sia
 * per confermare le modifiche fatte è necessario premere il pulsante OK
 * 
 * @author koldar
 * @version 1.0
 */
public final class MapLayerAdder extends ObjectAdderInformationContainer<MapLayer>{

	//FIXME agigungere un modo per far vedere il poligono che si sta creando!!!
	
	/**indica la forma che il nuovo MapLayer deve assumere*/
	private Polygon mapLayerShape;
	/**indica l'insieme dei punti che l'utente ha premuto*/
	private Vector<Point> userPoint;
	/**indica lo strato su cui si stanno effettuando le operazioni*/
	private int currentStratum;
	
	/**indica il corpo base che le chiavi hanno in comune nella sessione di inserimento di MapLayer. MapLayer
	 *  inseriti nella stessa sessione di inserimento hanno {@link #basekey} coincidente ma numeri progressivi diversi*/
	private String basekey;
	/**indica il numero progressivo da concatenare a {@link #basekey} in caso in cui si vogliano aggiungere MapLayer uguali nella stessa
	 * sessione di inserimento*/
	private int numberObjectToAdd;
	/**se TRUE indica che è possibile inserire più MapLayer durante la stessa sessione di inserimento foreground nella mappa.  Di default è FALSE*/
	private boolean speedInsertEnable;
	
	public MapLayerAdder(Display whereToAdd,MapLayer _objectToAdd, GameMap map,int currentstratum,String basekey) {
		super(whereToAdd, _objectToAdd, map);
		this.userPoint=new Vector<Point>(0,1);
		this.numberObjectToAdd=0;
		this.speedInsertEnable=false;
		this.currentStratum=currentstratum;
		this.basekey=basekey;
	}

	/**se l'utente esegue un double click mentre sta inserendo un MapLayer allora
	 * il software dovrebbe inserire nel poligono il punto indicato dal double click e
	 * chiudere il poligono, inserendo di fatto il nuovo MapLayer
	 */
	@Override
	public void doubleClick(MouseEvent arg0) {
		this.leftClick(arg0);
		this.enterTyped(new KeyEvent(this.whereToAdd,KeyEvent.KEY_TYPED,arg0.getWhen(),0,KeyEvent.VK_UNDEFINED,'\n'));
	}

	/**aggiunge il punto corrente al poligono rappresentante
	 * la forma del MapLayer
	 */
	public void leftClick(MouseEvent arg0) {
		if (this.whereToAdd.getPoints()==0){
			this.whereToAdd.setRepaintOnMouseMoved(true);
		}
		int mapx=arg0.getX()/(this.map.getMapresolution());
		int mapy=arg0.getY()/(this.map.getMapresolution());
		this.whereToAdd.addPoint(new Point(mapx,mapy));
		this.userPoint.add(new Point(mapx,mapy));
	}

	/**toglie l'ultimo punto in {@link #userPoint}. Se tale
	 * punto non esiste, non fa nulla
	 * 
	 */
	public void rightClick(MouseEvent arg0) {
		try{
			this.whereToAdd.removelastPoint();
			this.userPoint.remove(this.userPoint.lastElement());
		}catch (ArrayIndexOutOfBoundsException error){
			//non bisogna fare nulla ^^
		}
		if (this.whereToAdd.getPoints()==0){
			this.whereToAdd.setRepaintOnMouseMoved(false);
		}
	}


	public void unknownClick(MouseEvent arg0) {
	}

	/**conferma il poligono creatosi e resetta le varibaili in modo da poterne inserire un altro
	 * 
	 */
	public void enterTyped(KeyEvent arg0) {
		this.mapLayerShape=new Polygon();
		for (int i=0;i<this.userPoint.size();i++){
			this.mapLayerShape.addPoint(this.userPoint.get(i).x,this.userPoint.get(i).y);
		}
		MapLayer copy=null;
		try {
			copy=(MapLayer) this.objectToAdd.clone();
			this.speedInsertEnable=true;
		} catch (CloneNotSupportedException error1) {
			this.speedInsertEnable=false;
			copy=this.objectToAdd;
		}
		//impostazione del border del MapLayer
		copy.setShape(mapLayerShape);
		try{
			this.map.addUnsecureForeground(this.currentStratum,this.basekey+(this.numberObjectToAdd==0?"":Integer.toString(numberObjectToAdd)), copy);
		} catch (CoordinatesNotAcceptableException error){
			//non faccio nulla
		}
		//reset delle variabili in uso
		this.whereToAdd.clearPoints();
		this.userPoint.clear();
		//this.mapLayerShape.reset();
		if (this.speedInsertEnable){
			this.numberObjectToAdd++;
		}
		this.whereToAdd.setRepaintOnMouseMoved(false);
	}

	/**l'intero poligono viene eliminato e ricreato di nuovo.
	 * Se tale poligono era già vuoto, esce dalla modalità inserimento
	 * 
	 */
	public void escTyped(KeyEvent arg0) {
		this.whereToAdd.clearPoints();
		this.userPoint.clear();
		this.whereToAdd.setRepaintOnMouseMoved(false);
	}

	public void unkwnownTyped(KeyEvent arg0) {
	}

}
